﻿#pragma once
#ifndef _CR_STRING_
#define _CR_STRING_
#include <algorithm>
#include <iomanip>
#ifndef RC_INVOKED
#include <string>
// #include <xmemory>

#if defined(_MSC_VER) && _MSC_VER <= 1800

#include "core/tr1/crString.h"

#else

#pragma pack(push,_CRT_PACKING)
#pragma warning(push,_STL_WARNING_LEVEL)
#pragma warning(disable: _STL_DISABLED_WARNINGS)
// _STL_DISABLE_CLANG_WARNINGS
NS_CR_BEGIN

template<class _Elem> struct vl_char_traits
{	// properties of a string or stream unknown element
};

template<> struct vl_char_traits<char>
{
	static INLINE int ct_vscprintf(const char* _Format, va_list _ArgList)
	{
		return _vscprintf(_Format, _ArgList);
	}

	static INLINE int ct_vscprintf_s(char * _DstBuf, size_t _SizeInBytes, const char* _Format, va_list _ArgList)
	{
		return vsprintf_s(_DstBuf, _SizeInBytes, _Format, _ArgList);
	}

	static INLINE int ct_mstr_len(const char* _Source, const char* def_local)
	{
		return strlen(_Source);
	}

	static INLINE int ct_to_mstr(char* _DstBuf, size_t _SizeInBytes, const char* _Source, const char* def_local)
	{
#if defined(_MSC_VER) && _MSC_VER > 1400 
		strcpy_s(_DstBuf, _SizeInBytes, _Source);
#else
		strcpy(_DstBuf, _Source);
#endif
		return strlen(_Source);
	}

	static INLINE int ct_wstr_len(const char* _Source, const char* def_local)
	{
		setlocale(LC_ALL, def_local);
		int len = strlen(_Source) * 2 + 1;
		
		wchar_t * _DstBuf = new wchar_t[len];
#if defined(_MSC_VER) && _MSC_VER > 1400 
		size_t n = 0;
		mbstowcs_s(&n, _DstBuf, len, _Source, _TRUNCATE);
#else
		int n = mbstowcs(_DstBuf, _Source, len);
#endif
		setlocale(LC_ALL, "");
		delete[] _DstBuf;
		return n;
	}

	static INLINE int ct_to_wstr(wchar_t* _DstBuf, size_t _SizeInBytes, const char* _Source, const char* def_local)
	{
		setlocale(LC_ALL, def_local);
#if defined(_MSC_VER) && _MSC_VER > 1400 
		size_t n = 0;
		mbstowcs_s(&n, _DstBuf, _SizeInBytes, _Source, _TRUNCATE);
#else
		int n = mbstowcs(_DstBuf, _Source, _SizeInBytes);
#endif
		setlocale(LC_ALL, "");
		return n;
	}
};

template<> struct vl_char_traits<wchar_t>
{
	static INLINE int ct_vscprintf(const wchar_t* _Format, va_list _ArgList)
	{
		return _vscwprintf(_Format, _ArgList);
	}

	static INLINE int ct_vscprintf_s(wchar_t* _DstBuf, size_t _SizeInBytes, const wchar_t* _Format, va_list _ArgList)
	{
		return vswprintf_s(_DstBuf, _SizeInBytes, _Format, _ArgList);
	}

	static INLINE int ct_mstr_len(const wchar_t* _Source, const char* def_local)
	{
		setlocale(LC_ALL, def_local);
		int len = wcslen(_Source) * 2 + 1;
		char * _DstBuf = new char[len];

#if defined(_MSC_VER) && _MSC_VER > 1400 
		size_t n = 0;
		wcstombs_s(&n, _DstBuf, len, _Source, _TRUNCATE);
#else
		int n = wcstombs(_DstBuf, _Source, len);
#endif
		setlocale(LC_ALL, "");
		delete[] _DstBuf;
		return n;
	}

	static INLINE int ct_to_mstr(char* _DstBuf, size_t _SizeInBytes, const wchar_t* _Source, const char* def_local)
	{
		setlocale(LC_ALL, def_local);
#if defined(_MSC_VER) && _MSC_VER > 1400 
		size_t n = 0;
		wcstombs_s(&n, _DstBuf, _SizeInBytes, _Source, _TRUNCATE);
#else
		int n = wcstombs(_DstBuf, _Source, _SizeInBytes);
#endif
		setlocale(LC_ALL, "");
		return n;
	}

	static INLINE int ct_wstr_len(const wchar_t* _Source, const char* def_local)
	{
		return wcslen(_Source);
	}

	static INLINE int ct_to_wstr(wchar_t* _DstBuf, size_t _SizeInBytes, const wchar_t* _Source, const char* def_local)
	{
#if defined(_MSC_VER) && _MSC_VER > 1400 
		wcscpy_s(_DstBuf, _SizeInBytes, _Source);
#else
		wcscpy(_DstBuf, _Source);
#endif
		return wcslen(_Source);
	}
};

static _STD ios_base::fmtflags base_flag(int base)
{
	return (base == 16) ? (::std::ios_base::hex) :
		((base == 8) ? (::std::ios_base::oct) : (::std::ios_base::dec));
}

template<class _Elem, class _Traits, class _Alloc, class Type>
Type conver_to_number(::std::basic_stringstream<_Elem, _Traits, _Alloc>& ss, Type t, int base)
{
	ss.setf(base_flag(base));
	ss >> t;
	return t;
}

template<class _Elem, class _Traits, class _Alloc, class Type>
float conver_to_number(::std::basic_stringstream<_Elem, _Traits, _Alloc>& ss, float t, int base)
{
	ss >> t;
	return t;
}

template<class _Elem, class _Traits, class _Alloc, class Type>
double conver_to_number(::std::basic_stringstream<_Elem, _Traits, _Alloc>& ss, double t, int base)
{
	ss >> t;
	return t;
}

template<class _Elem, class _Traits, class _Alloc, class _ExTraits>
class base_string
	: public ::std::basic_string<_Elem, _Traits, _Alloc>
{
	using _Myt = base_string<_Elem, _Traits, _Alloc, _ExTraits>;
	using _MyBase = std::basic_string<_Elem, _Traits, _Alloc>;
	using _M_String = base_string<char, ::std::char_traits<char>, ::std::allocator<char>, vl_char_traits<char>>;
	using _W_String = base_string<wchar_t, ::std::char_traits<wchar_t>, ::std::allocator<wchar_t>, vl_char_traits<wchar_t>>;

	using _Alty = typename _MyBase::_Alty;
	using size_type = typename _MyBase::size_type;
	using const_pointer = typename _MyBase::const_pointer;

	using iterator = typename _MyBase::iterator;
	using const_iterator = typename _MyBase::const_iterator;

private:
	mutable int32_t _hash = 0;
public:
	INLINE base_string(const base_string& rhs)
		: _MyBase(rhs)
	{}

	INLINE base_string(const base_string& rhs, const _Alloc& al)
		: _MyBase(rhs, al)
	{}

	INLINE base_string() noexcept(_STD is_nothrow_default_constructible_v<_Alty>)
		: _MyBase()
	{}

	explicit INLINE base_string(const _Alloc& al) noexcept
		: _MyBase(al)
	{}

	INLINE base_string(const base_string& rhs, const size_type pos, const _Alloc& al = _Alloc())
		: _MyBase(rhs, pos, al)
	{}

	INLINE base_string(const base_string& rhs, const size_type pos, const size_type n, const _Alloc& al = _Alloc())
		: _MyBase(rhs, pos, n, al)
	{}

	INLINE base_string(const _Elem s)
		: _MyBase(1, s)
	{}

	INLINE base_string(const _Elem *s, size_type n)
		: _MyBase(s, n)
	{}

	INLINE base_string(const _Elem *s, size_type n, const _Alloc& al = _Alloc())
		: _MyBase(s, n, al)
	{}

	INLINE base_string(const _Elem *s, const _Alloc& al = _Alloc())
		: _MyBase(s, al)
	{}

	INLINE base_string(size_type n, const _Elem c, const _Alloc& al = _Alloc())
		: _MyBase(n, c, al)
	{}

	INLINE base_string(const_iterator first, const_iterator last, const _Alloc& al = _Alloc())
		: _MyBase(first, last, al)
	{}

	INLINE base_string(base_string&& rhs) noexcept
		: _MyBase(rhs)
	{}

	INLINE base_string(base_string&& rhs, const _Alloc& al)
		: _MyBase(rhs, al)
	{}


	INLINE base_string(const _MyBase& base)
		: _MyBase(base)
	{}

	base_string& operator=(const _Elem * const _Ptr)
	{
		_MyBase::operator=(_Ptr);
		return *this;
	}

	base_string& operator=(const base_string& _Right)
	{
		_MyBase::operator=(_Right);
		return *this;
	}

	base_string& operator=(const _MyBase& _Right)
	{
		_MyBase::operator=(_Right);
		return (*this);
	}

	template<class _Iter, class = _STD enable_if_t<_STD _Is_iterator_v<_Iter>>>
	base_string(_Iter _First, _Iter _Last, const _Alloc& _Al = _Alloc())
		: _MyBase(_First, _Last, _Al)
	{	// construct from [_First, _Last) with optional allocator
		_DEBUG_RANGE(_First, _Last);

	}

	//所有字符转为大写，改变自身  
	base_string& to_upper()
	{
		::std::transform(this->begin(), this->end(), this->begin(), toupper);
		return *this;
	}

	//所有字符转为大写，不改变自身  
	base_string& to_upper() const
	{
		base_string s;
		::std::transform(this->begin(), this->end(), s.begin(), toupper);
		return s;
	}

	//所有字符转为小写，改变自身  
	base_string& to_lower()
	{
		_STD transform(this->begin(), this->end(), this->begin(), tolower);
		return (*this);
	}

	//所有字符转为小写，不改变自身  
	base_string& to_lower() const
	{
		base_string s;
		_STD transform(this->begin(), this->end(), s.begin(), tolower);
		return s;
	}

	//替换字符串
	base_string& relpace(const base_string& target, const base_string& replacement)
	{
		if (target.empty())
			return (*this);
		size_type idx;
		while ((idx = this->find(target)) != -1)
			_MyBase::replace(idx, target.size(), replacement);
		return (*this);
	}

	//删除左边所有包含在target中的字符
	base_string& trim_left(const base_string& target)
	{
		while (!this->empty() && (target.find(*(this->begin())) != -1))
			this->erase(++(this.begin()));
		return (*this);
	}

	//删除右边所有包含在target中的字符
	base_string& trim_right(const base_string& target)
	{
		while (!this->empty() && target.find(*(this->rbegin())) != -1)
			this->erase(--(this->end()));
		
		return (*this);
	}

	//返回左边count个字符，count大于总长度则返回整个字符串
	base_string left(size_type count) const
	{
		return this->substr(0, count);
	}

	//返回右边count个字符，count大于总长度则返回整个字符串  
	base_string right(size_type count) const
	{
		auto _My_data = _STD addressof(this->_Get_data());
		return substr(_My_data->_Mysize < count ? 0 : _My_data->_Mysize - count);
	}

	//忽略大小写判断两个字符串是否相等  
	int compare_no_case(const base_string& rhs) const
	{
		return to_lower().compare(rhs.to_lower());
	}

	//判断字符串是否以制定字符串开头  
	bool begin_with(const base_string& rhs) const
	{
		return find(rhs) == size_type(0);
	}

	//判断字符串是否以制定字符串结尾  
	bool end_with(const base_string& rhs) const
	{
		auto _My_data = _STD addressof(this->_Get_data());
		
		if (rhs.size() > _My_data->_Mysize)
			return false;
		return compare(_My_data->_Mysize - rhs.size(), rhs.size(), rhs) == 0;
	}

	//转换为窄字节
	_M_String mstr(const char * local = "chs") const
	{
		_STD string s("");
		if (this->size() <= 0)
			return s;
		int len = _ExTraits::ct_mstr_len(this->_Get_data()._Myptr(), local);
		if (len <= 0)
			return s;

		s.resize(len);
		_ExTraits::ct_to_mstr(s._Get_data()._Myptr(), len, this->_Get_data()._Myptr(), local);
		return s.c_str();
	}

	//转换为宽字节
	_W_String wstr(const char * local = "chs") const
	{
		_STD wstring s(L"");
		if (this->size() <= 0)
			return s;
		int len = _ExTraits::ct_wstr_len(this->_Get_data()._Myptr(), local);
		if (len <= 0)
			return s;

		s.resize(len);
		_ExTraits::ct_to_wstr(s._Get_data()._Myptr(), len, this->_Get_data()._Myptr(), local);
		return s.c_str();
	}

#if _UNICODE
	_W_String tstr() const
	{
		return wstr();
	}
#else
	_M_String tstr() const
	{
		return mstr();
	}
#endif

	_STD vector<base_string> split(const _Elem c_sep = _Elem(','))
	{
		return split(base_string(c_sep));
	}

	_STD vector<base_string> split(const base_string& sep = _Elem(","))
	{
		_STD vector<base_string> vec = {};

		if (!this->empty())
		{
			base_string tmp;
			size_type pos_begin = this->find_first_not_of(sep);
			size_type pos_common = 0;

			while (pos_begin != base_string::npos)
			{
				pos_common = this->find(sep, pos_begin);
				if (pos_common != base_string::npos)
				{
					tmp = this->substr(pos_begin, pos_common - pos_begin);
					pos_begin = pos_common + sep.length();
				}
				else
				{
					tmp = this->substr(pos_begin);
					pos_begin = pos_common;
				}

				if (!tmp.empty())
				{
					vec.push_back(tmp);
					tmp.clear();
				}
			}
		}

		return vec;
	}

	//生成HashCode
	int32_t hash_code() const
	{
		int h = _hash;
		if (h == 0 && this->length() > 0 )
		{
			auto _My_data = _STD addressof(this->_Get_data());
			for (uint32_t i = 0; i < _My_data->_Mysize; ++i) {
				auto p =  _My_data->_Myptr()[i];
				h = 31 * h + p;
			}

			_hash = h;
		}
		return h;
	}

	//将字符串转为数字  
	//base:进制数。可以为8,10,16，如果其它值则强制为10。浮点数则忽略此参数
	template<typename T>
	T to_number(int base = 10) const
	{
		T t = T();
		_STD basic_stringstream<_Elem, _Traits, _Alloc> ss(this->_Get_data()._Myptr());
		return conver_to_number<_Elem, _Traits, _Alloc>(ss, t, base);
	}

	//将整数转化为字符串  
	//base:进制数。可以为8,10,16，如果其它值则强制为10  
	template<typename T>
	static base_string from_number(T number, int base = 10)
	{
		_STD basic_stringstream<_Elem, _Traits, _Alloc> ss;
		ss.setf(base_flag(base), _STD ios_base::basefield);
		ss << number;
		return ss.str();
	}

	//将float转化为字符串  
	//f:格式化参数。可以为'f','e','E','g','G'。'f'为定点数,'e'或'E'表示科学计数法  
	//  'g'或‘G’表示格式化为定点数或科学计数法，看哪一个表示方便。  
	//prec:小数点后的位数(定点数表示法)或总的有效位数(科学计数法)  
	static base_string from_number(float number, _Elem f = _Elem('g'), int prec = 6)
	{
		return from_number(static_cast<double>(number), f, prec);
	}

	//将double转化为字符串，参数解释同上  
	static base_string from_number(double number, _Elem f = _Elem('g'), int prec = 6)
	{
		_STD basic_stringstream<_Elem, _Traits, _Alloc> ss;
		ss << _STD setprecision(prec);
		if (_Traits::eq(f, _Elem('f')))
		{
			ss << _STD setiosflags(_STD ios_base::fixed);
		}
		else if (_Traits::eq(f, _Elem('e')) || _Traits::eq(f, _Elem('E')))
		{
			ss << _STD setiosflags(_STD ios_base::scientific);
		}
		ss << number;
		return ss.str();
	}
};

using string = base_string<char, ::std::char_traits<char>, ::std::allocator<char>, vl_char_traits<char>>;
using wstring = base_string<wchar_t, ::std::char_traits<wchar_t>, ::std::allocator<wchar_t>, vl_char_traits<wchar_t>>;

#ifdef _UNICODE
using tstring = base_string<wchar_t, ::std::char_traits<wchar_t>, ::std::allocator<wchar_t>, vl_char_traits<wchar_t>>;
#define tto_string  to_wstring 
#define tcout wcout
#else
using tstring = base_string<char, ::std::char_traits<char>, ::std::allocator<char>, vl_char_traits<char>>;
#define tto_string  to_string 
#define tcout cout
#endif

NS_CR_END

_STD_BEGIN

template<class _Elem,
	class _Traits,
	class _Alloc,
	class _ExTraits>
	struct hash<NS_CR base_string<_Elem, _Traits, _Alloc, _ExTraits>>
{
	size_t operator() (const NS_CR base_string<_Elem, _Traits, _Alloc, _ExTraits>& _Keyval) const noexcept
	{
		return (_Hash_array_representation(_Keyval.c_str(), _Keyval.size()));
	}
};

_STD_END

// _STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)

#endif
#endif /* RC_INVOKED */
#endif 